
package com.platform.api.security;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.platform.api.common.service.ByteService;
import com.platform.api.common.service.KsService;
import com.platform.common.core.Result;
import com.platform.common.util.Json;
import com.platform.security.constants.AppValue;
import com.platform.security.enums.App;
import com.platform.security.exception.ServerException;
import com.platform.security.exception.UnknownGrantTypeException;
import com.platform.security.model.AppConnect;
import com.platform.security.service.AuthUserDetailsService;
import com.platform.security.service.UserConnect;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * 小程序登陆：此时principal为code
 * post:http://127.0.0.1:8086/login
 * {principal:code}
 */
@Component
@Slf4j
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private final AuthUserDetailsService authUserDetailsService;

    private final WxMaService wxMaService;

    @Autowired
    private ByteService byteService;

    @Autowired
    private KsService ksService;

    @Autowired
    public LoginAuthenticationFilter(AuthUserDetailsService authUserDetailsService, WxMaService wxMaService) {
        super("/login");
        this.authUserDetailsService = authUserDetailsService;
        this.wxMaService = wxMaService;
    }

    //子类通过实现 attemptAuthentication 来尝试认证处理
    //认证成功后，将会将成功认证的信息 Authentication 保存到线程本地 SecurityContext中
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {

        Integer systemType = StringUtils.isNotBlank(request.getHeader("systemType")) ? Integer.valueOf(request.getHeader("systemType")) : 0;

        if (!ServletUtil.METHOD_POST.equals(request.getMethod())) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        String requestBody = getStringFromStream(request);

        if (StrUtil.isBlank(requestBody)) {
            throw new ServerException("无法获取输入信息");
        }

        MiniAppAuthenticationToken authentication = Json.parseObject(requestBody, MiniAppAuthenticationToken.class);
        String code = String.valueOf(authentication.getPrincipal());
        UserConnect loadedUser = null;

        WxMaJscode2SessionResult session = null;
        AppConnect appConnect = new AppConnect();
        String openid = null;
        Result loginResult = null;
        try {

            if (App.MINI.value().intValue() == systemType) {
                //微信
                session = wxMaService.getUserService().getSessionInfo(code);
                openid = session.getOpenid();
                appConnect.setSysAppId(App.MINI.value());
            } else if (App.BYTE.value().intValue() == systemType) {
                //抖音
                loginResult = byteService.loginForDy(code, null);
                appConnect.setSysAppId(App.BYTE.value());
                if(loginResult.getCode() == 200){
                    openid = loginResult.getData().toString();
                }
                appConnect.setSysAppId(App.BYTE.value());
            }else if (App.KUAISHOU.value().intValue() == systemType) {
                //快手
                loginResult = ksService.loginForKs(code);
                if(loginResult.getCode() == 200){
                    openid = loginResult.getData().toString();
                }
                appConnect.setSysAppId(App.KUAISHOU.value());
            }else{
                throw new UnknownGrantTypeException("未知授权方式");
            }

            loadedUser = authUserDetailsService.loadUserByAppIdAndBizUserIdB(AppValue.getAppValue(systemType), openid);
        } catch (WxErrorException e) {
            throw new ServerException(e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (loadedUser == null) {
            if(StringUtils.isEmpty(openid)){
                throw new ServerException("登录失败");
            }
            appConnect.setBizUserId(openid);
            appConnect.setOpenid(openid);
            appConnect.setRegTime(new Date());
            appConnect.setSysAppId(Integer.valueOf(systemType));
            authUserDetailsService.insertUserIfNecessary(appConnect);
            loadedUser = authUserDetailsService.loadUserByAppIdAndBizUserId(AppValue.getAppValue(systemType), appConnect.getBizUserId());
        }
        MiniAppAuthenticationToken result = new MiniAppAuthenticationToken(loadedUser, authentication.getCredentials());
        result.setDetails(authentication.getDetails());
        return result;
    }


    private String getStringFromStream(HttpServletRequest req) {
        ServletInputStream is;
        try {
            is = req.getInputStream();
            int nRead = 1;
            int nTotalRead = 0;
            byte[] bytes = new byte[10240];
            while (nRead > 0) {
                nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
                if (nRead > 0) {
                    nTotalRead = nTotalRead + nRead;
                }
            }
            return new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    //注入AuthenticationManager来处理子类中定义的 authenticationToken
    @Override
    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    //子类通过注入successHandler 和failureHandler来进行相应处理
    @Override
    @Autowired
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        super.setAuthenticationSuccessHandler(successHandler);
    }

    @Override
    @Autowired
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        super.setAuthenticationFailureHandler(failureHandler);
    }
}
